use crate::{error::Error, from_expr::FromExpr};

pub trait NamedFieldValueParser: Sized {
    fn parse(meta: &syn::Meta) -> syn::Result<Self>;
}

impl<T: FromExpr> NamedFieldValueParser for T {
    fn parse(meta: &syn::Meta) -> syn::Result<Self> {
        if let syn::Meta::NameValue(nv) = meta {
            let value = T::from_expr(&nv.value)?;
            return Ok(value);
        }
        let name = quote::ToTokens::to_token_stream(&meta).to_string();
        Err(Error::unsupported_format(&name).into())
    }
}

#[derive(Debug)]
pub struct Marker;

impl NamedFieldValueParser for Marker {
    fn parse(meta: &syn::Meta) -> syn::Result<Self> {
        if let syn::Meta::Path(_) = meta {
            return Ok(Marker);
        }
        let name = quote::ToTokens::to_token_stream(&meta).to_string();
        Err(Error::unsupported_format(&name).into())
    }
}

pub trait UnnamedFieldParser: Sized {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self>;
}

pub trait SynParser: syn::parse::Parse {}

impl SynParser for syn::Expr {}
impl SynParser for Box<syn::Expr> {}
impl SynParser for syn::Lit {}
impl SynParser for Option<syn::Lit> {}
impl SynParser for syn::LitInt {}
impl SynParser for Option<syn::LitInt> {}
impl SynParser for syn::LitFloat {}
impl SynParser for Option<syn::LitFloat> {}
impl SynParser for syn::LitBool {}
impl SynParser for Option<syn::LitBool> {}
impl SynParser for syn::LitStr {}
impl SynParser for Option<syn::LitStr> {}
impl SynParser for syn::Path {}
impl SynParser for Box<syn::Path> {}
impl SynParser for syn::Type {}
impl SynParser for Box<syn::Type> {}
impl SynParser for syn::FieldsNamed {}
impl SynParser for syn::FieldsUnnamed {}
impl SynParser for syn::Ident {}
impl SynParser for Box<syn::Ident> {}

impl<T: SynParser> UnnamedFieldParser for T {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        stream.parse()
    }
}
